#include <QUrl>
#include "sm-global.h"
#include "line-edit-delegate.h"
#include "server-section-model.h"
#include "settings.h"
#include "spin-box-delegate.h"
#include "standard-table-model.h"
#include "value-result.h"

ServerSectionModel::ServerSectionModel(QObject *parent) :
    StandardTableSectionModel(parent)
{
    m_idColumnCount = 0;
}

void ServerSectionModel::initialize()
{
    LineEditDelegate* nameDelegate = new LineEditDelegate();
    LineEditDelegate* addressDelegate = new LineEditDelegate();
    SpinBoxDelegate* portDelegate = new SpinBoxDelegate();
    portDelegate->setRange(0, 65535);
    portDelegate->setDefaultValue(8080);
    m_delegates.insert(NameColumn, nameDelegate);
    m_delegates.insert(AddressColumn, addressDelegate);
    m_delegates.insert(PortColumn, portDelegate);
    emit initialized();
}

QVariant ServerSectionModel::id (int row, int column) const
{
    Q_UNUSED(column);
    return row;
}

ValueResult *ServerSectionModel::canAddData (QVariantList dataList)
{
    Q_ASSERT(dataList.size() == 3);
    for (int i = 0; i < dataList.size(); i++)
    {
        ValueResult* result = canSetField(dataList.at(i), i);
        if (result->hasError())
            return result;
        else
            delete result;
    }

    return canSetRow(dataList);
}

ValueResult* ServerSectionModel::canUpdateData (QVariant value, int row, int column)
{
    ValueResult* result = canSetField(value, column, row);
    if (result->hasError())
        return result;
    else
        delete result;

    QVariantList dataList;
    for (int i = 0; i < column; i++)
        dataList << index(row, i).data();
    dataList << value;
    for (int i = column+1; i < columnCount(); i++)
        dataList << index(row, i).data();

    return canSetRow(dataList, row);
}

ValueResult* ServerSectionModel::canSetField (QVariant value, int column, int row)
{
    Q_UNUSED(row);
    ValueResult* result = new ValueResult(this);
    if (column == NameColumn)
    {
        QString name = value.toString();
        if (name.isEmpty())
            result->setError("Nazwa serwera jest pusta.", SmGlobal::DataInvalidError);
        else
            result->setValue(true);
    }
    else if (column == AddressColumn)
    {
        QUrl address = value.toUrl();
        if (address.isEmpty())
            result->setError("Adres serwera jest pusty.", SmGlobal::DataInvalidError);
        else if (!address.isValid())
            result->setError("Adres serwera jest nieprawidłowy.", SmGlobal::DataInvalidError);
        else
            result->setValue(true);
    }
    else if (column == PortColumn)
    {
        bool ok = false;
        int port = value.toInt(&ok);
        if (!ok || port < 0 || port > 65535)
            result->setError("Port serwera jest nieprawidłowy.", SmGlobal::DataInvalidError);
        else
            result->setValue(true);
    }
    return result;
}

ValueResult *ServerSectionModel::canSetRow (QVariantList dataList, int row)
{
    QString address = dataList.at(AddressColumn).toString();
    int port = dataList.at(PortColumn).toInt();
    ValueResult* result = new ValueResult(this);
    for (int i = 0; i < rowCount(); i++)
    {
        if (i == row)
            continue;

        if (address == m_internalModel->index(i, AddressColumn).data().toString()
            && port == m_internalModel->index(i, PortColumn).data().toInt())
        {
            result->setError("Serwer o takich danych już istnieje.", SmGlobal::DataInvalidError);
            return result;
        }
    }

    result->setValue(true);
    return result;
}

bool ServerSectionModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    Q_UNUSED(role);
    ValueResult* result = canUpdateData(value, index.row(), index.column());
    if (result->hasError())
    {
        emit notifyHint("Nie można edytować danych.", result->error().text());
        return false;
    }
    delete result;
    updateData(value, index.row(), index.column());
    return true;
}

void ServerSectionModel::loadData()
{
#ifdef DEVELOPMENT_BUILD
{
    Settings defaultSettings;
    defaultSettings.beginGroup("ServerSectionModel");
    if (!defaultSettings.beginReadArray("servers"))
    {
        defaultSettings.endArray();
        defaultSettings.beginWriteArray("servers");
        defaultSettings.setArrayIndex(0);
        defaultSettings.setValue("name", "lokalny");
        defaultSettings.setValue("address", "localhost");
        defaultSettings.setValue("port", 8080);
        defaultSettings.setArrayIndex(1);
        defaultSettings.setValue("name", "zdalny");
        defaultSettings.setValue("address", "srv-proj.ntdll.net");
        defaultSettings.setValue("port", 8080);
        defaultSettings.endArray();
        defaultSettings.endGroup();
    }
}
#endif

    beginResetModel();
    m_internalModel->setColumnCount(3);
    Settings settings;
    settings.beginGroup(metaObject()->className());
    int size = settings.beginReadArray("servers");
    m_internalModel->setRowCount(size);

    for (int i = 0; i < size; i++)
    {
        settings.setArrayIndex(i);
        QString name = settings.value("name").toString();
        QString address = settings.value("address").toString();
        int port = settings.value("port").toInt();
        m_internalModel->setData(index(i, 0), name, Qt::DisplayRole);
        m_internalModel->setData(index(i, 1), address, Qt::DisplayRole);
        m_internalModel->setData(index(i, 2), port, Qt::DisplayRole);
        m_internalModel->setData(index(i, 0), name, Qt::UserRole);
        m_internalModel->setData(index(i, 1), address, Qt::UserRole);
        m_internalModel->setData(index(i, 2), port, Qt::UserRole);
    }
    setHeaderData(0, Qt::Horizontal, "Nazwa", Qt::DisplayRole);
    setHeaderData(1, Qt::Horizontal, "Adres", Qt::DisplayRole);
    setHeaderData(2, Qt::Horizontal, "Port", Qt::DisplayRole);
    endResetModel();

    emit loadDataFinished(true);
}

void ServerSectionModel::addData (QVariantList dataList)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_internalModel->appendRow(dataList);
    for (int i = 0; i < columnCount(); i++)
    {
        m_internalModel->setData(m_internalModel->index(rowCount()-1, i),
                                 m_internalModel->index(rowCount()-1, i).data(), Qt::UserRole);
    }
    endInsertRows();
    saveSettings();
}

void ServerSectionModel::updateData (QVariant data, int row, int column)
{
    m_internalModel->setData(index(row, column), data, Qt::DisplayRole);
    m_internalModel->setData(index(row, column), data, Qt::UserRole);
    emit dataChanged(index(row, column), index(row, column));
    saveSettings();
}

void ServerSectionModel::removeData(QVariantList dataList)
{
    beginResetModel();
    m_internalModel->removeRows(dataList);
    endResetModel();
    saveSettings();
}

void ServerSectionModel::removeData(QVariant data)
{
    beginRemoveRows(QModelIndex(), data.toInt(), data.toInt());
    m_internalModel->removeRow(data.toInt());
    endRemoveRows();
    saveSettings();
}

void ServerSectionModel::saveSettings()
{
    Settings settings;
    settings.beginGroup(metaObject()->className());
    settings.beginWriteArray("servers");
    for (int i = 0; i < rowCount(); i++)
    {
        settings.setArrayIndex(i);
        settings.setValue("name", index(i, NameColumn).data().toString());
        settings.setValue("address", index(i, AddressColumn).data().toString());
        settings.setValue("port", index(i, PortColumn).data().toInt());
    }
    settings.endArray();
}
